/*
Automatic clinic tests using a robot arm.
Copyright (C) 2010  CIC-CPC, CHU Gabriel Montpied
All other trademarks, logos and copyrights are the property
of their respective owners.

This file is part of cpc-painbot.

cpc-painbot is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

cpc-painbot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with cpc-painbot.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef METHODE_H
#define METHODE_H

#include <QObject>
#include <QVariant>

namespace seuil {

class Determination;

/*! Une Méthode de détermination.
    Selon la Détermination - ou d'autres critères, on peut utiliser une Méthode différente :
    Up \& Down, Potentiel Evoqué...
*/
class Methode : public QObject
{
Q_OBJECT

//! La Détermination en cours.
Q_PROPERTY(Determination* determination READ determination)

//! Indique si la méthode est terminée.
Q_PROPERTY(bool terminee READ isTerminee WRITE setTerminee NOTIFY termineeChange)

//! Valeur déterminée.
Q_PROPERTY(QVariant valeur READ valeur)

//! Unité de la valeur.
Q_PROPERTY(QString unite READ unite)

//! Type de la Méthode.
Q_PROPERTY(Type type READ type CONSTANT)

Q_ENUMS(Type)
public:
    //! Types de méthodes.
    enum Type { UpAndDown, WindUp };

    //! Nombre de types.
    static const int nbTypes = 2;

    /*! Convertit un type en une chaîne de caractères.
        \param[in] type Le Type à afficher
        \return Une chaîne correspondant au type.
    */
    static QString typeToString(Type type);

    /*! Crée une méthode à partir de son Type.
        Crée une Méthode à partir de son type.

        \param[in]  type    Type de la Méthode à créer.
        \param      parent  Parent de la Méthode créée.

        \retval 0 La Méthode n'existe pas.
        \retval Methode* Une méthode avec le type correspondant.
    */
    static Methode *creer(Type type, QObject *parent = 0);


    /*! Détermination associée.
        \return La Détermination courante.
    */
    Determination *determination() const { return determination_; }

    /*! Fin de la méthode.
        Une méthode se termine en cas d'erreur ou par une fin normale.
        \retval true La méthode est finie.
        \retval false La méthode est en cours.
    */
    bool isTerminee() const { return terminee_; }

    /*! Valeur déterminée.
        A l'issue de la méthode, une valeur est déterminée.
        \return La valeur déterminée par cette méthode.
    */
    virtual QVariant valeur() const = 0;

    /*! Unité utilisée.
        \return L'unité de la valeur.
    */
    virtual QString unite() const = 0;


    /*! Type de la méthode.
        \return Le Type de cette méthode.
    */
    Type type() const { return type_; }

signals:
    //! Fin normale de la méthode.
    void termineeChange(bool fini);

    /*! Fin avec erreur.
        \param raison La raison de cette erreur.
    */
    void erreur(const QString &raison);

    //! Prêt à procéder à la prochaine étape.
    void continuer();

public slots:
    /*! Fin de la Méthode.
        \param[in] finie Indique si la méthode est finie.
    */
    void setTerminee(bool finie) { terminee_ = finie; emit termineeChange(terminee_); }

    /*! Prépare la détermination.
        Prépare la Methode via cette Determination.
        \param determination La Détermination liée.
    */
    void preparer(Determination *determination);

    /*! Reçoit une information de douleur quantitative.
        Une Méthode est sensible à la douleur que ressent le patient.
        Par défaut, cette méthode ne fait rien.
        \param[in] douleur La douleur ressentie.
    */
    virtual void douleur(const QVariant &douleur) {}

protected:
    //! Constructeur.
    Methode(Type type, QObject *parent = 0);

    /*! Génère une erreur.
        Termine la méthode et émet un signal d'erreur.
        \param[in] raison Le message d'erreur.
    */
    inline void setErreur(const QString &raison) { setTerminee(true); emit erreur(raison); }

    /*! Algorithme concret. */
    virtual void determiner() = 0;

    Determination *determination_; //!< Détermination courante à effectuer.
    bool terminee_; //! Méthode terminée ou non.

    Type type_; //!< Type de cette méthode.
};

} // namespace seuil

#endif // METHODE_H
